package dp.mobile.system;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.util.Log;

/**
 * 
 * Singleton to wrap MediaPlayer (to play BGM) and SoundPool (to play SFX)
 *
 */

public class SoundManager {
	public SoundManager(Context ctx){
		//initialization
		mContext		= ctx;
		mSpoolHashMap	= new HashMap<String, Integer>();
		mSoundPool		= new SoundPool(6, AudioManager.STREAM_MUSIC, 0);
		
		mSharedPref = mContext.getSharedPreferences(Utilities.PREFERENCES, 0);
		mSharedPrefEditor= mSharedPref.edit();
		
		initVolumeFromSharedPref();
	}
	
	public static SoundManager instance(Context ctx){
		if(sInstance == null) sInstance = new SoundManager(ctx);
		return sInstance;
	}
	
	private void initSoundPool(){
		if(mSoundPool == null)
			mSoundPool = new SoundPool(6, AudioManager.STREAM_MUSIC, 0);
	}
	
	private void initVolumeFromSharedPref(){
		mBGMVolume	= mSharedPref.getFloat(BGMVolume, 1.0f);
		mSFXVolume	= mSharedPref.getFloat(SFXVolume, 1.0f);
		mIsMute		= mSharedPref.getBoolean(IS_MUTE, false);
	}
	
	private void putBGMVolToSharedPref(float vol){
		if(mSharedPrefEditor != null){
			mSharedPrefEditor.putFloat(BGMVolume, vol);
			mSharedPrefEditor.commit();
		}
	}
	
	private void putSFXVolToSharedPref(float vol){
		if(mSharedPrefEditor != null){
			mSharedPrefEditor.putFloat(SFXVolume, vol);
			mSharedPrefEditor.commit();
		}
	}
	
	private void putIsMuteToSharedPref(Boolean isMute){
		if(mSharedPrefEditor != null){
			mSharedPrefEditor.putBoolean(IS_MUTE, isMute);
			mSharedPrefEditor.commit();
		}
	}
	
	public void loadDefaultSFX(){
		String path;
		File file;
		
		initSoundPool();
		
		try {
			path = Utilities.SFX_FOLDER + "/build.ogg";
			if(!mSpoolHashMap.containsKey(path)){
				file = new File(path);
				mSpoolHashMap.put(path, mSoundPool.load(new FileInputStream(file).getFD(), 0, file.length(), 1));
			}
			
			path = Utilities.SFX_FOLDER + "/cancel.ogg";
			Log.d("SFX", "path = " + path);
			if(!mSpoolHashMap.containsKey(path)){
				file = new File(path);
				mSpoolHashMap.put(path, mSoundPool.load(new FileInputStream(file).getFD(), 0, file.length(), 1));
			}
			
			path = Utilities.SFX_FOLDER + "/cursor.ogg";
			if(!mSpoolHashMap.containsKey(path)){
				file = new File(path);
				mSpoolHashMap.put(path, mSoundPool.load(new FileInputStream(file).getFD(), 0, file.length(), 1));
			}
			
			path = Utilities.SFX_FOLDER + "/error.ogg";
			if(!mSpoolHashMap.containsKey(path)){
				file = new File(path);
				mSpoolHashMap.put(path, mSoundPool.load(new FileInputStream(file).getFD(), 0, file.length(), 1));
			}
			
			path = Utilities.SFX_FOLDER + "/select.ogg";
			if(!mSpoolHashMap.containsKey(path)){
				file = new File(path);
				mSpoolHashMap.put(path, mSoundPool.load(new FileInputStream(file).getFD(), 0, file.length(), 1));
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void playBGM(int bgmID, Boolean isLooping){
		stopBGM();
		
		mMedPlayer = MediaPlayer.create(mContext, bgmID);
		
		if(mIsMute)
			mMedPlayer.setVolume(0.0f, 0.0f);
		else
			mMedPlayer.setVolume(mBGMVolume, mBGMVolume);
		mMedPlayer.setLooping(isLooping);
		mMedPlayer.start();
	}
	
	public void playBGM(String bgmPath, Boolean isLooping){
		stopBGM();
		
		mMedPlayer = new MediaPlayer();
		try {
        	File file = new File(bgmPath);
        	mMedPlayer.setDataSource((new FileInputStream(file).getFD()));
			mMedPlayer.prepare();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		if(mIsMute)
			mMedPlayer.setVolume(0.0f, 0.0f);
		else
			mMedPlayer.setVolume(mBGMVolume, mBGMVolume);
		mMedPlayer.setLooping(isLooping);
		mMedPlayer.start();
	}
	
	public void playSFX(String sfxPath){
		stopSFX();
		
		initSoundPool();
		
		if(!mSpoolHashMap.containsKey(sfxPath)){
			File file = new File(sfxPath);
			try {
				mSpoolHashMap.put(sfxPath, mSoundPool.load(new FileInputStream(file).getFD(), 0, file.length(), 1));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		if(mIsMute){
			mSoundPool.setVolume(mSpoolHashMap.get(sfxPath), 0.0f, 0.0f);
			mSoundPool.play(mSpoolHashMap.get(sfxPath), 0.0f, 0.0f, 1, 0, 1f);
		}
		else{
			mSoundPool.setVolume(mSpoolHashMap.get(sfxPath), mSFXVolume, mSFXVolume);
			mSoundPool.play(mSpoolHashMap.get(sfxPath), mSFXVolume, mSFXVolume, 1, 0, 1f);
		}
		
	}
	
	public void stopBGM(){
		if(mMedPlayer != null){
			mMedPlayer.stop();
			
			mMedPlayer.release();
			mMedPlayer = null;
		}
	}
	
	public void stopSFX(){
		
	}
	
	public void stopAllSound(){
		stopBGM();
		stopSFX();
	}
	
	public void temporarySetMute(boolean isTemporaryMute){
		if(mMedPlayer != null){
			if(isTemporaryMute)
				mMedPlayer.setVolume(0.0f, 0.0f);
			else if(!mIsMute)
				mMedPlayer.setVolume(mBGMVolume, mBGMVolume);
		}
		
		if(mSoundPool != null){
			Object[] key = mSpoolHashMap.keySet().toArray();
			for(int i=0; i<key.length; ++i){
				if(isTemporaryMute)
					mSoundPool.setVolume(mSpoolHashMap.get(key[i].toString()), 0.0f, 0.0f);
				else if(!mIsMute)
					mSoundPool.setVolume(mSpoolHashMap.get(key[i].toString()), mSFXVolume, mSFXVolume);
			}
		}
	}
	
	public void setMute(Boolean isMute){
		mIsMute = isMute;
		putIsMuteToSharedPref(mIsMute);
		
		if(mIsMute){ //Mute all sound
			if(mMedPlayer != null)
				mMedPlayer.setVolume(0.0f, 0.0f);
			
			if(mSoundPool != null){
				Object[] key = mSpoolHashMap.keySet().toArray();
				for(int i=0; i<key.length; ++i){
					mSoundPool.setVolume(mSpoolHashMap.get(key[i].toString()), 0.0f, 0.0f);
				}
			}
		} else { //Unmute back to its previous volume
			setBGMVolume(mBGMVolume);
			setSFXVolume(mSFXVolume);
		}
	}
	
	public void setVolume(float vol){
		setBGMVolume(vol);
		setSFXVolume(vol);
	}
	
	public void setBGMVolume(float vol){
		//Set MediaPlayer volume
		mBGMVolume = vol;
		putBGMVolToSharedPref(vol);
		
		if(mMedPlayer != null)
			mMedPlayer.setVolume(mBGMVolume, mBGMVolume);
	}
	
	public void setSFXVolume(float vol){
		//Set SoundPool volume
		mSFXVolume = vol;
		putSFXVolToSharedPref(vol);
		
		if(mSoundPool != null){
			Object[] key = mSpoolHashMap.keySet().toArray();
			for(int i=0; i<key.length; ++i){
				mSoundPool.setVolume(mSpoolHashMap.get(key[i].toString()), mSFXVolume, mSFXVolume);
			}
		}
	}
	
	public void releasePool(){
		if(mSoundPool != null){
			mSoundPool.release();
			mSoundPool = null;
		}
	}
	
	public float getBGMVolume(){
		return mBGMVolume;
	}
	
	public float getSFXVolume(){
		return mSFXVolume;
	}
	
	public boolean isMute(){
		return mIsMute;
	}
	
	//DATA
	private static SoundManager sInstance;
	
	private Context		mContext;	
	private MediaPlayer	mMedPlayer;
	private SoundPool	mSoundPool;
	private HashMap<String, Integer> mSpoolHashMap;
	private Boolean		mIsMute;
	
	private float	mBGMVolume;
	private float	mSFXVolume;
	
	private SharedPreferences	mSharedPref;
	private Editor				mSharedPrefEditor;
	
	//FINAL STATIC
	public final static String BGMVolume = "BGM_VOLUME";
	public final static String SFXVolume = "SFX_VOLUME";
	public final static String IS_MUTE	 = "IS_MUTE";
}
